package gui;

import cmm.Executor;
import cmm.Lexer.Lexer;
import cmm.Lexer.Token;
import cmm.Lexer.TokenType;
import cmm.Parser.Parser;
import cmm.Seman.FourCode;
import cmm.Seman.Seman;
import org.w3c.dom.css.RGBColor;

import javax.swing.*;
import javax.swing.text.*;
import javax.swing.text.rtf.RTFEditorKit;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.*;
import java.sql.Connection;
import java.util.LinkedList;
import static cmm.Lexer.Lexer.*;

/**
 * Created by Xxy on 2017/12/10.
 */
public class GUI{
    private JFrame frame;
    private JTextPane Output;
    private JPanel panel1;
    private JTextPane Input;
    private JLabel label1;
    private JLabel label2;
    private JScrollPane Jscroll1;
    private JScrollPane Jscroll2;
    public JTextPane Console;
    private static File file;
    private static String filePath;
    private static String fileName;
    private boolean changed;



    public GUI() {
        frame = new JFrame("GUI");
        frame.setContentPane(panel1);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JMenuBar jb = createMenuBar();
        frame.setJMenuBar(jb);
        changed = false;
        LineNumberHeaderView header = new LineNumberHeaderView();
        header.setFont(new Font("Arial",0,16));
        header.setLineHeight(24);
        Jscroll1.setRowHeaderView(header);
        //initialize input text pane
        m_context = new StyleContext();
        m_doc = new DefaultStyledDocument(m_context);
        Input.setDocument(m_doc);
        keyAttr = new SimpleAttributeSet();
        StyleConstants.setForeground(keyAttr, Color.BLUE);
        opAttr = new SimpleAttributeSet();
        StyleConstants.setForeground(opAttr, Color.MAGENTA);
        normalAttr = new SimpleAttributeSet();
        StyleConstants.setForeground(normalAttr, Color.BLACK);
        Input.addKeyListener(new KeyAdapter() {
            @Override
            public void keyTyped(KeyEvent e) {
                super.keyTyped(e);
                changed = true;
                styler();
            }
        });
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        new GUI();
    }
    public JMenuBar createMenuBar() {
        JMenuBar menuBar = new JMenuBar();
        JMenu menuFile = new JMenu("File");
        JMenuItem itemNew = new JMenuItem("New");
        JMenuItem itemOpen = new JMenuItem("Open");
        JMenuItem itemSave = new JMenuItem("Save");
        JMenuItem itemSaveAs = new JMenuItem("Save As");
        menuFile.setFont(new Font("Microsoft YaHei UI",0,18));
        itemNew.setFont(new Font("Microsoft YaHei UI",0,18));
        itemOpen.setFont(new Font("Microsoft YaHei UI",0,18));
        itemSave.setFont(new Font("Microsoft YaHei UI",0,18));
        itemSaveAs.setFont(new Font("Microsoft YaHei UI",0,18));
        menuFile.add(itemNew);
        menuFile.add(itemOpen);
        menuFile.add(itemSave);
        menuFile.add(itemSaveAs);
        menuBar.add(menuFile);
        itemNew.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (changed == true){
                    int i = JOptionPane.showConfirmDialog(null, "Do you want to save the current file");
                    if(i == JOptionPane.YES_OPTION) {
                        if (file == null){
                            JFileChooser dialog = new JFileChooser();
                            dialog.setDialogTitle("Save");
                            int result = dialog.showSaveDialog(null);
                            if (result == JFileChooser.APPROVE_OPTION) {
                                file = dialog.getSelectedFile();
                                fileName = file.getName();
                                if (fileName == null || fileName.trim().length() == 0) {
                                    JOptionPane.showMessageDialog(null, "File name is blank");
                                }
                                if (file.isFile()) {
                                    fileName = file.getName();
                                    filePath = file.getPath();
                                } else {
                                    file = dialog.getCurrentDirectory();
                                    filePath = file.getPath() + java.io.File.separator + fileName + ".cmm";
                                }
                                file = new File(filePath);
                                label1.setText(filePath);
                                if(file.exists()) {
                                    int j = JOptionPane.showConfirmDialog(null, "Do you want to overwrite the existing file");
                                    if(j == JOptionPane.YES_OPTION);
                                    else   return ;
                                    label1.setText(filePath);
                                }
                                saveFile();
                            }
                        }
                        else saveFile();
                    }
                    else if(i == JOptionPane.NO_OPTION){
                        Output.setText(null);
                        Input.setText(null);
                    }
                    else   return ;
                }
                file = null;
                changed = false;
                label1.setText(null);
                Output.setText(null);
                Input.setText(null);
            }
        });
        itemOpen.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Open");
                JFileChooser dialog = new JFileChooser();
                dialog.setDialogTitle("Open File");
                if (changed == true){
                    int i = JOptionPane.showConfirmDialog(null, "Do you want to save the current file");
                    if(i == JOptionPane.YES_OPTION) {
                        if (file == null) {
                            dialog.setDialogTitle("Save");
                            int result = dialog.showSaveDialog(null);
                            if (result == JFileChooser.APPROVE_OPTION) {
                                file = dialog.getSelectedFile();
                                fileName = file.getName();
                                if (fileName == null || fileName.trim().length() == 0) {
                                    JOptionPane.showMessageDialog(null, "File name is blank");
                                }
                                if (file.isFile()) {
                                    fileName = file.getName();
                                    filePath = file.getPath();
                                } else {
                                    file = dialog.getCurrentDirectory();
                                    filePath = file.getPath() + java.io.File.separator + fileName + ".cmm";
                                }
                                file = new File(filePath);
                                label1.setText(filePath);

                                if (file.exists()) {
                                    int j = JOptionPane.showConfirmDialog(null, "Do you want to overwrite the existing file");
                                    if (j == JOptionPane.YES_OPTION) ;
                                    else return;
                                    label1.setText(filePath);
                                }
                            }
                        }
                        saveFile();
                    }
                    else if(i == JOptionPane.NO_OPTION){
                        Output.setText(null);
                        Input.setText(null);
                    }
                    else   return ;
                }
                int result = dialog.showOpenDialog(null);
                if (result == JFileChooser.APPROVE_OPTION) {
                    file = dialog.getSelectedFile();
                    filePath = file.getAbsolutePath();
                    fileName = file.getName();
                    System.out.println("Path："+filePath+";\nName："+fileName);
                    try {
                        label1.setText(filePath);
                        FileInputStream inputStream = new FileInputStream(file);
                        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                        String line =bufferedReader.readLine();
                        StringBuffer buffer =new StringBuffer();
                        while(line !=null){
                            buffer.append(line);
                            buffer.append("\n");
                            line = bufferedReader.readLine();
                        }
                        inputStream.close();
                        Input.setText(buffer.toString());
                        overallStyler();
                    } catch (FileNotFoundException e1) {
                        JOptionPane.showMessageDialog(null, "File not found");
                    } catch (IOException e1) {
                        JOptionPane.showMessageDialog(null, "File not correctly read");
                    }
                }
                else {
                    System.out.println("No file selected");
                }
                changed = false;
            }
        });
        itemSaveAs.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Save As");
                JFileChooser dialog = new JFileChooser();
                dialog.setDialogTitle("Save As");
                int result = dialog.showSaveDialog(itemSave);
                if (result == JFileChooser.APPROVE_OPTION) {
                    file =dialog.getSelectedFile();
                    fileName = file.getName();
                    if(fileName==null|| fileName.trim().length()==0){
                        JOptionPane.showMessageDialog(null, "File name is blank");
                    }
                    if(file.isFile()){
                        fileName = file.getName();
                        filePath = file.getPath();
                    }
                    else {
                        file = dialog.getCurrentDirectory();
                        filePath = file.getPath()+java.io.File.separator+fileName+".cmm";
                    }
                    file =new File(filePath);
                    label1.setText(filePath);
                    if(file.exists()) {
                        int i = JOptionPane.showConfirmDialog(null, "Do you want to overwrite the existing file");
                        if(i == JOptionPane.YES_OPTION);
                        else   return ;
                        label1.setText(filePath);
                    }
                }
                saveFile();
            }
        });
        itemSave.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Save");
                JFileChooser dialog = new JFileChooser();
                if (file == null) {
                    dialog.setDialogTitle("Save");
                    int result = dialog.showSaveDialog(null);
                    if (result == JFileChooser.APPROVE_OPTION) {
                        file = dialog.getSelectedFile();
                        fileName = file.getName();
                        if (fileName == null || fileName.trim().length() == 0) {
                            JOptionPane.showMessageDialog(null, "File name is blank");
                        }
                        if (file.isFile()) {
                            fileName = file.getName();
                            filePath = file.getPath();
                        } else {
                            file = dialog.getCurrentDirectory();
                            filePath = file.getPath() + java.io.File.separator + fileName + ".cmm";
                        }
                        file = new File(filePath);
                        label1.setText(filePath);

                        if (file.exists()) {
                            int i = JOptionPane.showConfirmDialog(null, "Do you want to overwrite the existing file");
                            if (i == JOptionPane.YES_OPTION) ;
                            else return;
                            label1.setText(filePath);
                        }
                    }
                }
                saveFile();
            }
        });

        JMenu menuRun = new JMenu("Run");
        JMenuItem itemLex = new JMenuItem("Lexical Analysis");
        JMenuItem itemSyntax = new JMenuItem("Syntax Analysis");
        JMenuItem itemSemantic = new JMenuItem("Semantic Analysis");
        JMenuItem itemRun = new JMenuItem("Run");
        menuRun.setFont(new Font("Microsoft YaHei UI",0,18));
        itemLex.setFont(new Font("Microsoft YaHei UI",0,18));
        itemSyntax.setFont(new Font("Microsoft YaHei UI",0,18));
        itemSemantic.setFont(new Font("Microsoft YaHei UI",0,18));
        itemRun.setFont(new Font("Microsoft YaHei UI",0,18));
        menuRun.add(itemLex);
        menuRun.add(itemSyntax);
        menuRun.add(itemSemantic);
        menuRun.add(itemRun);
        menuBar.add(menuRun);
        itemLex.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    if (changed | file ==null){
                        JOptionPane.showMessageDialog(null, "You need to save the file before running");
                        return;
                    }
                    runLex();
                } catch (Exception e1) {
                    Output.setText(e1.toString());
                }
            }
        });
        itemSyntax.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    if (changed | file ==null){
                        JOptionPane.showMessageDialog(null, "You need to save the file before running");
                        return;
                    }
                    runSyntax();
                } catch (Exception e1) {
                    Output.setText(e1.toString());
                }
            }
        });
        itemSemantic.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    if (changed | file ==null){
                        JOptionPane.showMessageDialog(null, "You need to save the file before running");
                        return;
                    }
                    runSemantic();
                } catch (Exception e1) {
                    Output.setText(e1.toString());
                }
            }
        });
        itemRun.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    if (changed | file ==null){
                        JOptionPane.showMessageDialog(null, "You need to save the file before running");
                        return;
                    }
                    runInterpreter();
                } catch (Exception e1) {
                    Output.setText(e1.toString());
                }

            }
        });
        return menuBar;
    }

    private void runLex() throws Exception{
        FileInputStream inputStream = new FileInputStream(file);
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        Lexer lexer = new Lexer(bufferedReader);
        lexer.lex();
        StringBuffer buffer = lexer.formStringBuffer();
        inputStream.close();
        Output.setText(buffer.toString());
    }
    private void runSyntax() throws Exception{
        FileInputStream inputStream = new FileInputStream(file);
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        Lexer lexer = new Lexer(bufferedReader);
        lexer.lex();
        Parser parser = new Parser();
        parser.parse(new LinkedList<Token>(lexer.tokens));
        StringBuffer buffer = parser.formStringBuffer();
        inputStream.close();
        Output.setText(buffer.toString());
    }
    private void runSemantic() throws Exception{
        FileInputStream inputStream = new FileInputStream(file);
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        Lexer lexer = new Lexer(bufferedReader);
        lexer.lex();
        Parser parser = new Parser();
        parser.parse(new LinkedList<Token>(lexer.tokens));

        Seman seman = new Seman();
        StringBuffer buffer = new StringBuffer();
        LinkedList<FourCode> codes= seman.generateCode(parser);
        for (int i = 0; i < codes.size(); i++) {
            buffer.append( i + " :  " + codes.get(i).toString());
            buffer.append("\n");
        }
        inputStream.close();
        Output.setText(buffer.toString());
    }
    private void runInterpreter() throws Exception{
        FileInputStream inputStream = new FileInputStream(file);
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        Lexer lexer = new Lexer(bufferedReader);
        lexer.lex();
        Parser parser = new Parser();
        parser.parse(new LinkedList<Token>(lexer.tokens));
        Seman seman = new Seman();
        StringBuffer buffer = new StringBuffer();
        LinkedList<FourCode> codes= seman.generateCode(parser);
        Executor executor = new Executor(codes);
        buffer = executor.getBuffer();
        Output.setText(buffer.toString());
    }

    private void saveFile(){
        try {
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)));
            writer.write(Input.getText());
            writer.flush();
            writer.close();
        } catch (FileNotFoundException e1) {
            JOptionPane.showMessageDialog(null, "A exception occurs"+e1.getMessage());
        } catch (IOException e1) {
            e1.printStackTrace();
        }
        changed = false;
    }

    protected StyleContext m_context;
    protected DefaultStyledDocument m_doc;
    private MutableAttributeSet keyAttr,normalAttr,opAttr;
    private MutableAttributeSet inputAttributes = new RTFEditorKit().getInputAttributes();
    private void styler(){
        try {
            String s = null;
            Element root = m_doc.getDefaultRootElement();
            int cursorPos = Input.getCaretPosition();
            int line = root.getElementIndex(cursorPos);
            Element para = root.getElement(line);
            int start = para.getStartOffset();
            int end = para.getEndOffset() - 1;
            s = m_doc.getText(start, end - start+1);
            int i = 0;
            int xStart = 0;
            BufferedReader reader = new BufferedReader(new StringReader(s));
            Lexer lex = new Lexer(reader);
            lex.lex();
            m_doc.setCharacterAttributes(start, s.length(),normalAttr, false);
            inputAttributes.addAttributes(normalAttr);
            for (Token token:lex.getTokens()){

                if (ReserveWord.containsValue(token.getType())){
                    xStart = token.getPosition();
                    m_doc.setCharacterAttributes(start+xStart-1, token.getValue().length(), keyAttr, false);
                }
//                else if(token.getType() == TokenType.ID){
//                    xStart = token.getPosition();
//                    m_doc.setCharacterAttributes(start+xStart-token.getValue().length()-1, token.getValue().length(), opAttr, false);
//                }
//                else if (Operator.containsValue(token.getType())){
//                    xStart = token.getPosition();
//                    m_doc.setCharacterAttributes(start+xStart-token.getValue().length()-1, token.getValue().length(), opAttr, false);
//                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    private void overallStyler(){
        try {
            int lineNumber = Input.getText().split("\\n").length;
            for (int i = 0; i<lineNumber;i++){
                String s = null;
                Element root = m_doc.getDefaultRootElement();
                int cursorPos = Input.getCaretPosition();
                Element para = root.getElement(i);
                int start = para.getStartOffset();
                int end = para.getEndOffset() - 1;
                s = m_doc.getText(start, end - start+1);
                int xStart = 0;
                BufferedReader reader = new BufferedReader(new StringReader(s));
                Lexer lex = new Lexer(reader);
                lex.lex();
                m_doc.setCharacterAttributes(start, s.length(),normalAttr, false);
                inputAttributes.addAttributes(normalAttr);
                for (Token token:lex.getTokens()){
                    if (ReserveWord.containsValue(token.getType())){
                        xStart = token.getPosition();
                        m_doc.setCharacterAttributes(start+xStart-1, token.getValue().length(), keyAttr, false);
                    }
//                    else if(token.getType() == TokenType.ID){
//                        xStart = token.getPosition();
//                        m_doc.setCharacterAttributes(start+xStart-token.getValue().length()-1, token.getValue().length(), opAttr, false);
//                    }
//                else if (Operator.containsValue(token.getType())){
//                    xStart = token.getPosition();
//                    m_doc.setCharacterAttributes(start+xStart-token.getValue().length()-1, token.getValue().length(), opAttr, false);
//                }
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}
